/**
 * GioCMS
 * 
 * LICENSE
 *
 * This source file is subject to the GNU GENERAL PUBLIC LICENSE Version 2 
 * that is bundled with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.gnu.org/licenses/gpl-2.0.txt
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@ninhgio.com so we can send you a copy immediately.
 * 
 * @copyright	Copyright (c) 2010-2011 GioCMS (http://cms.ninhgio.com)
 * @license		http://www.gnu.org/licenses/gpl-2.0.txt GNU GENERAL PUBLIC LICENSE Version 2
 * @author		NinhGio - ninhgio@gmail.com
 * @since		1.0
 */

'Gio.Core.ToolBox'.namespace();

Gio.Core.ToolBox = function(cls) {
	this._cls       = cls;
	this._module    = null;
	this._displayed = false;
	this._title 	= null;
	this._lang		= null;
};

Gio.Core.ToolBox.PREFIX_ID = 'Gio_ToolBox_';

/**
 * We can not use the different methods to handle the drop event to the same 
 * dropped elements.
 * Because each time the dropped element call the drop handler in each Toolbox, 
 * it will override the previous one.
 * This method is to fix this issue. 
 *  
 * @param object droppedElement
 * @param string handler
 * @param event
 * @param ui
 * @return void
 */
Gio.Core.ToolBox.callDropHandler = function(droppedElement, handler, event, ui) {
	var methods = $(droppedElement).data('dropHandlerMethods');
	if (methods == null) {
		methods = [];
	}
	if (methods.indexOf(handler) == -1) {
		methods.push(handler);
	}
	$(droppedElement).data('dropHandlerMethods', methods);
	
	for (var i in methods) {
		var f = methods[i];
		eval(f)(droppedElement, event, ui);
	}
};

Gio.Core.ToolBox.prototype = {
	setCurrentModule: function(module) {
		this._currModule = module;
		return this;
	},
	
	setTitle: function(title) {
		this._title = title;
		return this;
	},
	
	setLang: function(lang) {
		this._lang = lang;
		return this;
	},
	
	/**
	 * @param string cls The Toolbox class
	 */
	show: function() {
		if (this._displayed) {
			$('#' + Gio.Core.ToolBox.PREFIX_ID + this._cls).show();
			return;
		}
		var self        = this;
		//this._displayed = true;
		this._displayed = false;
		
		var cls         = this._cls;
		var currModule  = this._currModule;
		var names       = this._cls.split('_');
		var title 		= this._title;
		var lang		= this._lang;
		
		var baseUrl     = Gio.Core.Widget.Loader.baseUrl;
		baseUrl         = baseUrl.replace(/\/+$/, '');
		var url = (Gio.Core.Widget.Loader.userUrl != '') ? Gio.Core.Widget.Loader.userUrl : baseUrl + '/core/widget/ajax';
		$.ajaxq('core_toolbox', {
			url: url,
			type: 'POST',
			data: {
				mod: names[0], 
				name: names[2],
				act: 'show',
				params: 'currModule=' + currModule + '|lang=' + lang
			},
			success: function(response) {
				var res    = $.evalJSON(response);
				var output = [];
				
				output.push('<div class="g_a_ui_toolbox_header">',
								'<h3>', title, '</h3>',
								'<div class="g_a_ui_toolbox_buttons">',
									'<a href="javascript: void(0);" class="g_a_ui_toolbox_toggle g_a_ui_toolbox_minimum"><span>-</span></a>',
									'<a href="javascript: void(0);" class="g_a_ui_toolbox_close"><span>x</span></a>',
								'</div>',
							'</div>',
							'<div class="g_a_ui_toolbox_content">', res.content, '</div>');
				
				var div = $('<div/>');
				$(div).attr('id', Gio.Core.ToolBox.PREFIX_ID + cls)
					  .addClass('g_a_toolbox').html(output.join(''))
					  .draggable({
						  handle: '.g_a_ui_toolbox_header'
					  });
				
				/**
				 * Toggle toolbox
				 */
				$(div).find('a.g_a_ui_toolbox_toggle').toggle(function() {
					$(this).removeClass('g_a_ui_toolbox_minimum').addClass('g_a_ui_toolbox_maximum');
					$(this).parents('.g_a_toolbox').find('div.g_a_ui_toolbox_content').hide();
					$(this).parents('.g_a_toolbox_header').addClass('g_a_ui_toolbox_shadow');
				}, function() {
					$(this).removeClass('g_a_ui_toolbox_maximum').addClass('g_a_ui_toolbox_minimum');
					$(this).parents('.g_a_toolbox').find('div.g_a_ui_toolbox_content').show();
					$(this).parents('.g_a_toolbox_header').removeClass('g_a_ui_toolbox_shadow');
				});
				
				/**
				 * Allows user to toggle DIV sections inside the toolbox
				 */
				$(div).find('.g_a_ui_helper_line a').click(function() {
					if ($(this).hasClass('hide')) {
						$(this).addClass('show').removeClass('hide');
						$(this).parent().parent().next().slideDown('slow');
					} else {
						$(this).addClass('hide').removeClass('show');
						$(this).parent().parent().next().slideUp('slow');
					}
					return false;
				});
				
				/**
				 * Hide the toolbox
				 */
				$(div).find('a.g_a_ui_toolbox_close').click(function() {
					//self.hide();
					self.remove();
				});
				
				$('body').append($(div));
				$(div).find('.g_a_ui_helper_line a').click();

				/**
				 * Load CSS, JS files
				 */
				self._loadCssFiles(res.cssFiles);
				self._loadJsFiles(res.jsFiles, res.jsScripts);
			}
		});
	},
	
	/**
	 * Remove the toolbox
	 * 
	 * @return void
	 */
	remove: function() {
		$('#' + Gio.Core.ToolBox.PREFIX_ID + this._cls).remove();
		Gio.Core.ToolBox.Manager.getInstance().remove(this._cls);
	},
	
	/**
	 * Hide the toolbox
	 * 
	 * @return void
	 */
	hide: function() {
		$('#' + Gio.Core.ToolBox.PREFIX_ID + this._cls).hide();
	},
	
	/**
	 * Load CSS files
	 * 
	 * @param array cssFiles
	 * @return void
	 */
	_loadCssFiles: function(cssFiles) {
		for (var i in cssFiles) {
			if ($('head').find('link[type="text/css"][href="' + cssFiles[i] + '"]').length == 0) {
				$('<link rel="stylesheet" type="text/css" href="' + cssFiles[i] + '" />').appendTo('head');
			}
		}
	},
	
	/**
	 * Load JS files
	 * 
	 * @param array jsFiles
	 * @param array jsScripts
	 * @param int index
	 * @return void
	 */
	_loadJsFiles: function(jsFiles, jsScripts) {
		var self = this;
		if (jsFiles != null && jsFiles.length > 0) {
			var file = jsFiles[0];
			if (file != null 
				&& 
				($('head').find('script[src="' + file + '"]').length == 0
				|| $('body').find('script[src="' + file + '"]').length == 0)) {
				$('<script type="text/javascript" src="' + file + '"></script>').appendTo('body');
				
				$.getScript(file, function() {
					/**
					 * IMPORTANT NOTES:
					 * There are some approach methods to append the external JS to the body:
					 * 
					 * 1)
					 * $('<script/>').attr('type', 'text/javascript').attr('src', file).appendTo('body');
					 * - Does NOT work
					 * 
					 * 2)
					 * var s  = document.createElement('script');
					 * s.type = 'text/javascript';
					 * s.src  = file;
					 * document.body.appendChild(s);
					 * - Works perfectly!
					 * - See: http://stackoverflow.com/questions/610995/jquery-cant-append-script-element
					 * 
					 * 3) (See the following code)
					 * - Works perfectly!
					 */
					jsFiles.splice(0, 1);
					self._loadJsFiles(jsFiles, jsScripts);
				});
			} else {
				jsFiles.splice(0, 1);
				self._loadJsFiles(jsFiles, jsScripts);
			}
		} else {
			self._loadJsScripts(jsScripts);
		}
	},
	
	/**
	 * Load JS scripts
	 * 
	 * @param array jsScripts
	 * @return void
	 */
	_loadJsScripts: function(jsScripts) {
		for (i in jsScripts) {
			var script = jsScripts[i];
			if (script != null) {
				$('body').find('script[type="text/javascript"][id="' + this._cls + '"]').remove();
				/**
				 * IMPORTANT NOTES:
				 * There are some ways to append the JS script to the body:
				 * 
				 * 1) 
				 * $('<script type="text/javascript" id="' + this._cls + '">' + script + '</script>').appendTo('body');
				 * - Works on Firefox
				 * - Does NOT work on Chrome
				 * Use the second method to solve this issue
				 * (http://forum.jquery.com/topic/chrome-not-executing-an-appended-script-block)
				 * 
				 * 2) 
				 * $('<script>').attr('type', 'text/javascript').attr('id', this._cls).html(script).appendTo('body');
				 * - Works on Firefox/Chrome
				 * - But this does NOT work with some particual cases, such as the ImageToolbox widget
				 * 
				 * 3) (See the following code)
				 * - Works perfectly!
				 * - See: http://stackoverflow.com/questions/610995/jquery-cant-append-script-element
				 */
				var s  = document.createElement('script');
				s.type = 'text/javascript';
				s.id   = this._cls;
				s.text = script;
				document.body.appendChild(s);
			}
		}
	}
};

/**
 * Manage ToolBox
 */
'Gio.Core.ToolBox.Manager'.namespace();

Gio.Core.ToolBox.Manager = (function() {
	var _instance = null;
	
	function Manager() {
		var _toolBoxes = [];
		
		/**
		 * Get the toolbox instance
		 * 
		 * @param string cls The toolbox class
		 * @return Gio.Core.ToolBox
		 */
		this.getToolbox = function(cls) {
			if (_toolBoxes[cls] == null) {
				_toolBoxes[cls] = new Gio.Core.ToolBox(cls);				
			}
			return _toolBoxes[cls];
		};
		
		/**
		 * Remove the toolbox
		 * 
		 * @param string cls
		 * @return void
		 */
		this.remove = function(cls) {
			delete _toolBoxes[cls];
		};
		
		/**
		 * Hide the toolbox
		 * 
		 * @param string cls
		 * @return void
		 */
		this.hide = function(cls) {
			if (_toolBoxes[cls] != null) {
				_toolBoxes[cls].hide();
			}
		};
	};
	
	return new function() {
		/**
		 * Singleton method
		 * 
		 * @return Gio.Core.ToolBox.Manager
		 */
		this.getInstance = function() {
			if (_instance == null) {
				_instance 			  = new Manager();
				_instance.constructor = null;
			}
			return _instance;
		};
	};
})();
